package cn.wsn2018.tools.dao.impl;

import cn.wsn2018.tools.common.CommonValue;
import cn.wsn2018.tools.dao.LogsInfoDao;
import cn.wsn2018.tools.model.Log.LogInfo;
import cn.wsn2018.tools.model.Log.LogsInfo;
import cn.wsn2018.tools.util.StringUtil;
import com.mongodb.BasicDBObject;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.DateOperators;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;

/**
 * @author gmz.
 * @date 2018/12/14.
 * @time 15:09
 */
@Repository("logsInfoDao")
public class LogsInfoDaoImpl implements LogsInfoDao {
    private Logger logger = Logger.getLogger(LogsInfoDaoImpl.class.getName());

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 查询某操作员的所有日志信息,按时间降序排列
     * @param username
     * @return
     */
    @Override
    public List<LogsInfo> listLogsInfoByUser(String username,int pageNum,int pageSize){
        Query query = new Query();
        query.addCriteria(Criteria.where("username").is(username));
        query.with(new Sort(Sort.Direction.DESC,"createTime"));
        query.skip((pageNum-1)*pageSize).limit(pageSize);
        List<LogsInfo> logsInfoList = mongoTemplate.find(query,LogsInfo.class,"logsInfo");
        return logsInfoList;
    }

    /**
     * 实现分页,查询某一页的日志信息，并且该信息是针对所有操作员
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public  List<LogsInfo> listLogsByPageNum(int pageNum,int pageSize){
        Query query = new Query();
        //排序
        query.with(new Sort(Sort.Direction.DESC,"createTime"));
        query.skip((pageNum-1)*pageSize).limit(pageSize);
        List<LogsInfo> datas = mongoTemplate.find(query, LogsInfo.class,"logsInfo");
        return datas;
    }

    /**
     * 用于test，插入一条日志信息
     * @param logsInfo
     * @return
     */
    @Override
    public boolean saveLogsInfo(LogsInfo logsInfo){
        JSONObject result = JSONObject.fromObject(mongoTemplate.insert(logsInfo,"logsInfo"));
        String id = result.optString("id");
        if(id!=null&&!"".equals(id)) {
            return true;
        }
        else {
            return false;
        }
    }

    /**
     * 根据时间范围查询所有操作员的日志信息
     * @param fromTime
     * @param toTime
     * @return
     */
    @Override
    public List<LogsInfo> listLogsInfoByTime(int pageNum,int pageSize,String fromTime,String toTime){
        Query query = new Query();
        query.addCriteria(Criteria.where("createTime").gte(fromTime).lte(toTime));
        //排序
        query.with(new Sort(Sort.Direction.DESC,"createTime"));
        query.skip((pageNum-1)*pageSize).limit(pageSize);
        List<LogsInfo> datas = mongoTemplate.find(query, LogsInfo.class,"logsInfo");

        return datas;
    }

    /**
     * 根据时间范围、操作员，查询日志信息
     * @param username
     * @param fromTime
     * @param toTime
     * @return
     */
    @Override
    public List<LogsInfo> listLogsInfoByTimeAndName(String username,int pageNum,int pageSize,String fromTime,String toTime){
        Query query = new Query();
        //添加查询条件
        query.addCriteria(Criteria.where("username").is(username));
        query.addCriteria(Criteria.where("createTime").gte(fromTime).lte(toTime));
        //排序
        query.with(new Sort(Sort.Direction.DESC,"createTime"));
        query.skip((pageNum-1)*pageSize).limit(pageSize);
        List<LogsInfo> datas = mongoTemplate.find(query, LogsInfo.class,"logsInfo");

        return datas;
    }

    @Override
    public List<LogsInfo> listLogsInfoByCond(String username,Integer eventType, int pageNum, int pageSize, String fromTime, String toTime,
                                             String timeSort,String usernameSort,String typeSort,String eventTypeSort) {

        Query query = new Query();
        //添加查询条件
        conditionQueryCheck(query,username,fromTime,toTime,eventType);

        //排序
        conditionQuerySort(query,timeSort,usernameSort,typeSort,eventTypeSort);


//        query.with(new Sort(Sort.Direction.DESC,"username"));
//        query.with(new Sort(Sort.Direction.DESC,"createTime"));
//        query.with(Sort.by(
//                Sort.Order.desc("createTime"),
//                Sort.Order.asc("username")
//                )
//        );
        query.skip((pageNum-1)*pageSize).limit(pageSize);
        List<LogsInfo> datas = mongoTemplate.find(query, LogsInfo.class,"logsInfo");

        return datas;
    }

    @Override
    public Long countLogsInfoByCond(String username, String fromTime, String toTime,Integer eventType) {
        Query query = new Query();
        conditionQueryCheck(query,username,fromTime,toTime,eventType);

        long count = mongoTemplate.count(query, "logsInfo");
        return count;
    }


    /**
     * @Description: 保存日志
     * @Param: [logInfo, collectionName]
     * @return: boolean
     * @Author: SongDaisong
     * @Date: 21:01
     */
    //保存和分页的万能dao
    @Override
    public boolean saveLogInfo(LogInfo logInfo, String collectionName) {

        String id = mongoTemplate.insert(logInfo, collectionName).getId();
        if(id!=null&&!"".equals(id)) {
            return true;
        }
        else {
            return false;
        }
    }


    /**
     * @Description:className:指定日志类
     * @Param: [className, pageNum, pageSize, fromTime, toTime]
     * @return: java.util.List<cn.wsn2018.tools.model.Log.LogsInfo>
     * @Author: SongDaisong
     * @Date: 21:01
     */
    @Override
    public List<LogsInfo> listLogInfoByCond(String username,int pageNum, int pageSize, String fromTime, String toTime,Class className,
                                            String collectionName,String moduleNameSort,String warnTypeSort,String warnLevelSort,String timeSort,
                                            String errorModuleSort,String usernameSort,String operatTypeSort) {
        Query query = new Query();
        conditionQueryCheck(query,username,fromTime,toTime,null);
        //排序
        WarnOrErrorConditionSort(query,moduleNameSort,warnTypeSort,warnLevelSort,timeSort,errorModuleSort,usernameSort,operatTypeSort,collectionName);

        query.skip((pageNum-1)*pageSize).limit(pageSize);
        List<LogsInfo> logInfoList = mongoTemplate.find(query, className, collectionName);
        return logInfoList;
    }

    /**
     * 方便日志转存，无条件查询所有日志
     * @param className
     * @param collectionName
     * @return
     */
    @Override
    public List<LogsInfo> listAllLogsByCond(Class className,String collectionName){
        Query query = new Query();
        query.with(new Sort(Sort.Direction.DESC,"createTime"));
        List<LogsInfo> logInfoList = mongoTemplate.find(query, className, collectionName);
        return logInfoList;
    }

    /**
     * @Description: 简单统计条件内符合的记录数
     * @Param: [username, fromTime, toTime, collectionName]
     * @return: java.lang.Long
     * @Author: SongDaisong
     * @Date:  2020/2/18 20:47
     */
    @Override
    public Long coutLogInfoByCond(String username, String fromTime, String toTime, String collectionName) {
        Query query = new Query();

        conditionQueryCheck(query,username,fromTime,toTime,null);

        long count = mongoTemplate.count(query, collectionName);

        return count;
    }

    /**
     * @Description:返回统计信息，用于图表显示
     * @Param: [fromTime, toTime, name, eventType]
     * @return: java.util.List
     * @Author: SongDaisong
     * @Date:  2020/2/18 18:58
     */
    @Override
    public List<Document> statisticalBusLogs(String fromTime, String toTime, String name, Integer eventType) {
        //时间条件
        Criteria timeCriteria = timeCriteria(fromTime,toTime);

        Criteria eventTypeCriteria = new Criteria();
        Criteria nameCriteria = new Criteria();

        //事件类型
        if(CommonValue.LOG_TYPE_BUS==eventType){
            eventTypeCriteria.andOperator(Criteria.where("eventType").is(0));
        }else if(CommonValue.LOG_TYPE_SYS==eventType){
            eventTypeCriteria.andOperator(Criteria.where("eventType").is(1));
        }

        //查询的用户
        if(!StringUtil.isEmptyString(name)){
            nameCriteria.andOperator(Criteria.where("username").is(name));
        }

        Aggregation aggregation = Aggregation.newAggregation(
                //Aggregation.group("type").count().as("总数")
                //Aggregation.match(Criteria.where("createTime").gte(fromTime).lte(toTime)),
                //Aggregation.sort(Sort.Direction.DESC,"createTime"),
                Aggregation.match(timeCriteria),
                Aggregation.match(eventTypeCriteria),
                Aggregation.match(nameCriteria),
                Aggregation.project("createTime","eventType").andExpression("substr(createTime,0,10)").as("date"),
                Aggregation.group("date","eventType").count().as("totalNum"),
                Aggregation.sort(Sort.Direction.ASC,"date")
        );

        AggregationResults<Document> results = mongoTemplate.aggregate(aggregation, "logsInfo", Document.class);
        List<Document> documents = results.getMappedResults();
        System.out.println(documents);

        return documents;
    }

    /**
     * @Description:  统计告警日志
     * @Param: [fromTime, toTime, name, warnType]
     * @return: void
     * @Author: SongDaisong
     * @Date:  2020/2/21 16:16
     */
    @Override
    public List<Document> statisticalWarnLogs(String fromTime, String toTime, String name, Integer warnType) {

        //时间条件
        Criteria timeCriteria = timeCriteria(fromTime,toTime);

        Criteria warnTypeCriteria = new Criteria();
        Criteria nameCriteria = new Criteria();

        //事件类型
        if(warnType!=null){
            if(0==warnType){
                warnTypeCriteria.andOperator(Criteria.where("warningType").is(CommonValue.WARNING_TYPE_0));
            }else if(1==warnType){
                warnTypeCriteria.andOperator(Criteria.where("warningType").is(CommonValue.WARNING_TYPE_1));
            }
        }

        //查询的用户
        if(!StringUtil.isEmptyString(name)){
            nameCriteria.andOperator(Criteria.where("username").is(name));
        }

        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(timeCriteria),
                Aggregation.match(warnTypeCriteria),
                Aggregation.match(nameCriteria),
                Aggregation.project("createTime","warningType").andExpression("substr(createTime,0,10)").as("date"),
                Aggregation.group("date","warningType").count().as("totalNum"),
                Aggregation.sort(Sort.Direction.ASC,"date")
        );

        AggregationResults<Document> warningLogInfo = mongoTemplate.aggregate(aggregation, "warningLogInfo", Document.class);
        List<Document> mappedResults = warningLogInfo.getMappedResults();

//        Iterator<Document> iterator = mappedResults.iterator();
//        while (iterator.hasNext()){
//            Document next = iterator.next();
//            System.out.println(next);
//        }
        return mappedResults;

    }

    /**
     * @Description: 统计错误日志
     * @Param: [fromTime, toTime, name, moduleType]
     * @return: java.util.List<org.bson.Document>
     * @Author: SongDaisong
     * @Date:  2020/2/23 15:32
     */
    @Override
    public List<Document> statisticalErrorLogs(String fromTime, String toTime, String name, Integer moduleType) {

        Criteria timeCriteria = timeCriteria(fromTime, toTime);
        Criteria nameCriteria = new Criteria();
        Criteria moduleCriteria = new Criteria();
        if(moduleType!=null){
            if(moduleType==0){
                //登录部分
                moduleCriteria.andOperator(Criteria.where("moduleName").is(CommonValue.LOGIN_LOGINFO));
            }else if(moduleType==1){
                //操作员
                moduleCriteria.andOperator(Criteria.where("moduleName").is(CommonValue.OPERATOR_MODULE));
            }else if(moduleType==2){
                //业务审计员
                moduleCriteria.andOperator(Criteria.where("moduleName").is(CommonValue.AUDITOR_MODULE));
            }else if(moduleType==3){
                //系统审计员
                moduleCriteria.andOperator(Criteria.where("moduleName").is(CommonValue.SYS_AUDITOR_MODULE));
            }else if(moduleType==4){
                //系统管理员
                moduleCriteria.andOperator(Criteria.where("moduleName").is(CommonValue.ADMIN_MODULE));
            }
        }

        if(!StringUtil.isEmptyString(name)){
            nameCriteria.andOperator(Criteria.where("username").is(name));
        }

        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(timeCriteria),
                Aggregation.match(moduleCriteria),
                Aggregation.match(nameCriteria),
                Aggregation.project("createTime","moduleName").andExpression("substr(createTime,0,10)").as("date"),
                Aggregation.group("date","moduleName").count().as("totalNum"),
                //Aggregation.group("date").count().as("totalNum"),
                //Aggregation.group("moduleName").count().as("num"),
                Aggregation.sort(Sort.Direction.ASC,"date")

        );

        AggregationResults<Document> errorLogInfo = mongoTemplate.aggregate(aggregation, "errorLogInfo", Document.class);
        List<Document> mappedResults = errorLogInfo.getMappedResults();

        return mappedResults;
    }

    /******************************************************************************/
    //业务日志
    static void conditionQueryCheck(Query query,String username,String fromTime,String toTime,Integer eventType){
        /** 
        * @Description: 封装的业务日志条件添加
        * @Param: [query, username, fromTime, toTime] 
        * @return: void 
        * @Author: SongDaisong 
        * @Date:  2020/2/6 16:57
        */ 
        if(!username.isEmpty()){
            query.addCriteria(Criteria.where("username").is(username));
        }
        //时间范围
        if((!fromTime.isEmpty()) && (!toTime.isEmpty()) ){
            query.addCriteria(Criteria.where("createTime").gte(fromTime).lte(toTime));
        }else if(!fromTime.isEmpty()){
            query.addCriteria(Criteria.where("createTime").gte(fromTime));
        }else if (!toTime.isEmpty()){
            query.addCriteria(Criteria.where("createTime").lte(toTime));
        }

        //事件类型

        if(CommonValue.LOG_TYPE_BUS==eventType){
            query.addCriteria(Criteria.where("eventType").is(0));
        }else  if(CommonValue.LOG_TYPE_SYS==eventType){
            query.addCriteria(Criteria.where("eventType").is(1));
        }

    }

    static void conditionQuerySort(Query query,String timeSort,String usernameSort,String typeSort,String eventTypeSort){
        /** 
        * @Description: 日志排序条件
        * @Param: [query, timeSort, usernameSort,typeSort]
        * @return: void 
        * @Author: SongDaisong 
        * @Date:  2020/2/7 17:06
        */

        if(!StringUtil.isEmptyString(usernameSort)){
            //按照用户名排序
            if(CommonValue.AESC.equals(usernameSort)){
                //升序
                query.with(Sort.by(Sort.Order.asc("username"),Sort.Order.desc("createTime")));
            }else if(CommonValue.DESC.equals(usernameSort)){
                //降序
                query.with(Sort.by(Sort.Order.desc("username"),Sort.Order.desc("createTime")));
            }
        }

        if(!StringUtil.isEmptyString(timeSort)){
            //时间排序不为空
            if(CommonValue.AESC.equals(timeSort)){
                //变为升序
               query.with(new Sort(Sort.Direction.ASC, "createTime"));
            }else if(CommonValue.DESC.equals(timeSort)){
                query.with(new Sort(Sort.Direction.DESC, "createTime"));
            }
        }

        if(!StringUtil.isEmptyString(typeSort)){
            //按操作类型排序
            if(CommonValue.AESC.equals(typeSort)){
                query.with(Sort.by(Sort.Order.asc("type"),Sort.Order.desc("createTime")));
            }else if(CommonValue.DESC.equals(typeSort)){
                query.with(Sort.by(Sort.Order.desc("type"),Sort.Order.desc("createTime")));
            }
        }
        if(!StringUtil.isEmptyString(eventTypeSort)){
            //按事件类型排序
            if(CommonValue.AESC.equals(eventTypeSort)){
                query.with(Sort.by(Sort.Order.asc("eventType"),Sort.Order.desc("createTime")));
            }else if(CommonValue.DESC.equals(eventTypeSort)){
                query.with(Sort.by(Sort.Order.desc("eventType"),Sort.Order.desc("createTime")));
            }
        }

        if(StringUtil.isEmptyString(timeSort)&&StringUtil.isEmptyString(usernameSort)
                && StringUtil.isEmptyString(typeSort)&&StringUtil.isEmptyString(eventTypeSort)) {
            //无任何排序要求，就按照时间降序
            query.with(new Sort(Sort.Direction.DESC, "createTime"));
        }


    }

    //系统日志
    static void WarnOrErrorConditionSort(Query query,String moduleNameSort, String warnTypeSort, String warnLevelSort, String timeSort,
                                  String errorModuleSort,String usernameSort,String operatTypeSort,String collectionName) {
        /**
         * @Description: 告警错误日志排序
         * @Param: [moduleNameSort, warnTypeSort, warnLevelSort, warnTimeSort]
         * @return: void
         * @Author: SongDaisong
         * @Date:  2020/2/9 15:04
         */
        if(CommonValue.WARN_COLLLECTION.equals(collectionName)){
            //告警日志
            if(!StringUtil.isEmptyString(timeSort)){
                //按照告警时间排序
                if(CommonValue.AESC.equals(timeSort)){
                    query.with(Sort.by(
                            Sort.Order.asc("createTime")
                    ));
                }else if(CommonValue.DESC.equals(timeSort)){
                    query.with(Sort.by(
                            Sort.Order.desc("createTime")
                    ));
                }
            }
            if(!StringUtil.isEmptyString(moduleNameSort)){
                //按照告警模块名
                if(CommonValue.AESC.equals(moduleNameSort)){
                    query.with(Sort.by(Sort.Order.asc("warningModuleName"),
                            Sort.Order.desc("createTime")));
                }else if(CommonValue.DESC.equals(moduleNameSort)){
                    query.with(Sort.by(
                            Sort.Order.desc("warningModuleName"),
                            Sort.Order.desc("createTime")
                    ));
                }
            }

            if(!StringUtil.isEmptyString(warnTypeSort)){
                //按照告警类型排序
                if(CommonValue.AESC.equals(warnTypeSort)){
                    query.with(Sort.by(
                            Sort.Order.asc("warningType"), Sort.Order.desc("createTime")
                    ));
                }else if(CommonValue.DESC.equals(warnTypeSort)){
                    query.with(Sort.by(
                            Sort.Order.desc("warningType"),
                            Sort.Order.desc("createTime")
                    ));
                }
            }
            if(!StringUtil.isEmptyString(warnLevelSort)){
                //按照告警的级别排序
                if(CommonValue.AESC.equals(warnLevelSort)){
                    query.with(Sort.by(
                            Sort.Order.asc("warningLevel"),
                            Sort.Order.desc("createTime")
                    ));
                }else if(CommonValue.DESC.equals(warnLevelSort)){
                    query.with(Sort.by(
                            Sort.Order.desc("warningLevel"), Sort.Order.desc("createTime")
                    ));
                }
            }
            if(!StringUtil.isEmptyString(usernameSort)){
                //按照告警的级别排序
                if(CommonValue.AESC.equals(usernameSort)){
                    query.with(Sort.by(
                            Sort.Order.asc("username"),
                            Sort.Order.desc("createTime")
                    ));
                }else if(CommonValue.DESC.equals(usernameSort)){
                    query.with(Sort.by(
                            Sort.Order.desc("username"), Sort.Order.desc("createTime")
                    ));
                }
            }

            if(StringUtil.isEmptyString(timeSort)
                    &&StringUtil.isEmptyString(moduleNameSort)&&StringUtil.isEmptyString(warnTypeSort)
                    &&StringUtil.isEmptyString(warnLevelSort)&&StringUtil.isEmptyString(usernameSort)){
                query.with(Sort.by(
                        Sort.Order.desc("createTime")
                ));
            }

        }

        if(CommonValue.ERROR_COLLLECTION.equals(collectionName)){
            //错误日志
            if(!StringUtil.isEmptyString(timeSort)){
                //按照时间排序
                if(CommonValue.AESC.equals(timeSort)){
                    query.with(Sort.by(Sort.Order.asc("createTime")));
                }else if(CommonValue.DESC.equals(timeSort)){
                    query.with(Sort.by(Sort.Order.desc("createTime")));
                }
            }
            if(!StringUtil.isEmptyString(errorModuleSort)){
                //按照模块名排序
                if(CommonValue.AESC.equals(errorModuleSort)){
                    query.with(Sort.by(Sort.Order.asc("moduleName"),Sort.Order.desc("createTime")));
                }else if(CommonValue.DESC.equals(errorModuleSort)){
                    query.with(Sort.by(Sort.Order.desc("moduleName"),Sort.Order.desc("createTime")));
                }
            }

            if(!StringUtil.isEmptyString(usernameSort)){
                //用户名排序
                if(CommonValue.AESC.equals(usernameSort)){
                    query.with(Sort.by(Sort.Order.asc("username"),Sort.Order.desc("createTime")));
                }else if(CommonValue.DESC.equals(usernameSort)){
                    query.with(Sort.by(Sort.Order.desc("username"),Sort.Order.desc("createTime")));
                }
            }

            if(!StringUtil.isEmptyString(operatTypeSort)){
                //操作类型排序
                if(CommonValue.AESC.equals(operatTypeSort)){
                    query.with(Sort.by(Sort.Order.asc("operatorType"),Sort.Order.desc("createTime")));
                }else if(CommonValue.DESC.equals(operatTypeSort)){
                    query.with(Sort.by(Sort.Order.desc("operatorType"),Sort.Order.desc("createTime")));
                }
            }

            if(StringUtil.isEmptyString(timeSort)&&StringUtil.isEmptyString(errorModuleSort)
                    &&StringUtil.isEmptyString(errorModuleSort)&&StringUtil.isEmptyString(operatTypeSort)){
                //都为空 默认是时间降序
                query.with(Sort.by(Sort.Order.desc("createTime")));
            }

        }


    }

    //时间Criteria
    static Criteria timeCriteria(String fromTime,String toTime){
        Criteria criteria = new Criteria();
        //时间范围
        if((!fromTime.isEmpty()) && (!toTime.isEmpty()) ){
            criteria.andOperator(Criteria.where("createTime").gte(fromTime).lte(toTime));
        }else if(!fromTime.isEmpty()){
            criteria.andOperator(Criteria.where("createTime").gte(fromTime));
        }else if (!toTime.isEmpty()){
            criteria.andOperator(Criteria.where("createTime").lte(toTime));
        }
        return  criteria;
    }



}
